#ifndef __FAT_LIST_H__
#define __FAT_LIST_H__

#ifndef FAT_ASSERT
	#define FAT_ASSERT(x)
#endif

#ifndef FAT_INLINE
	#define FAT_INLINE
#endif

//-----------------------------------------------------------------
// Types
//-----------------------------------------------------------------
struct fat_list;

struct fat_node
{
	struct fat_node	*previous;
	struct fat_node	*next;
};

struct fat_list
{
	struct fat_node	*head;
	struct fat_node	*tail;
};

//-----------------------------------------------------------------
// Macros
//-----------------------------------------------------------------
#define fat_list_entry(p, t, m)		p ? ((t *)((char *)(p)-(char*)(&((t *)0)->m))) : 0
#define fat_list_next(l, p)			(p)->next
#define fat_list_prev(l, p)			(p)->previous
#define fat_list_first(l)			(l)->head
#define fat_list_last(l)			(l)->tail
#define fat_list_for_each(l, p)		for ((p) = (l)->head; (p); (p) = (p)->next)

//-----------------------------------------------------------------
// Inline Functions
//-----------------------------------------------------------------

//-----------------------------------------------------------------
// fat_list_init: 
//-----------------------------------------------------------------
static FAT_INLINE void fat_list_init(struct fat_list *list)
{
	FAT_ASSERT(list);

	list->head = list->tail = 0;
}
//-----------------------------------------------------------------
// fat_list_remove: 
//-----------------------------------------------------------------
static FAT_INLINE void fat_list_remove(struct fat_list *list, struct fat_node *node) 
{
	FAT_ASSERT(list);
	FAT_ASSERT(node);

	if(!node->previous)
		list->head = node->next;
	else
		node->previous->next = node->next;

	if(!node->next)
		list->tail = node->previous;
	else
		node->next->previous = node->previous;
}
//-----------------------------------------------------------------
// fat_list_insert_after: 
//-----------------------------------------------------------------
static FAT_INLINE void fat_list_insert_after(struct fat_list *list, struct fat_node *node, struct fat_node *new_node) 
{
	FAT_ASSERT(list);
	FAT_ASSERT(node);
	FAT_ASSERT(new_node);

	new_node->previous = node;
	new_node->next = node->next;
	if (!node->next)
		list->tail = new_node;
	else
		node->next->previous = new_node;
	node->next = new_node;
}
//-----------------------------------------------------------------
// fat_list_insert_before: 
//-----------------------------------------------------------------
static FAT_INLINE void fat_list_insert_before(struct fat_list *list, struct fat_node *node, struct fat_node *new_node) 
{
	FAT_ASSERT(list);
	FAT_ASSERT(node);
	FAT_ASSERT(new_node);

	new_node->previous = node->previous;
	new_node->next = node;
	if (!node->previous)
		list->head = new_node;
	else
		node->previous->next = new_node;
	node->previous = new_node;
}
//-----------------------------------------------------------------
// fat_list_insert_first: 
//-----------------------------------------------------------------
static FAT_INLINE void fat_list_insert_first(struct fat_list *list, struct fat_node *node) 
{
	FAT_ASSERT(list);
	FAT_ASSERT(node);

	if (!list->head)
	{
		list->head = node;
		list->tail = node;
		node->previous = 0;
		node->next = 0;
	}
	else
		fat_list_insert_before(list, list->head, node);
}
//-----------------------------------------------------------------
// fat_list_insert_last: 
//-----------------------------------------------------------------
static FAT_INLINE void fat_list_insert_last(struct fat_list *list, struct fat_node *node) 
{
	FAT_ASSERT(list);
	FAT_ASSERT(node);

	if (!list->tail)
		fat_list_insert_first(list, node);
     else
		fat_list_insert_after(list, list->tail, node);
}
//-----------------------------------------------------------------
// fat_list_is_empty: 
//-----------------------------------------------------------------
static FAT_INLINE int fat_list_is_empty(struct fat_list *list)
{
	FAT_ASSERT(list);
	
	return !list->head;
}
//-----------------------------------------------------------------
// fat_list_pop_head: 
//-----------------------------------------------------------------
static FAT_INLINE struct fat_node * fat_list_pop_head(struct fat_list *list)
{
	struct fat_node * node;

	FAT_ASSERT(list);

	node = fat_list_first(list);
	if (node)
		fat_list_remove(list, node);
	
	return node;
}

#endif

